#include "immediate.h"

#include "vcache.h"

// Immediate mode operates one vertex at a time, we use
//  a single vertex object and inherit non-position values
//  from previous vertices.
//
//    e3dVertex...functions define the position of a vertex,
//    add it (including color, texcoords and normals) to the
//    vertex cache and begin a new vertex.
// 

e3dVertexCache* E3D_IMMEDIATE_VCACHE = NULL;
e3dIndexCache*  E3D_IMMEDIATE_ICACHE = NULL;
e3dVertex       E3D_IMMEDIATE_VTX;

void e3dBegin (e3dVertexCache* cache)
{
  E3D_IMMEDIATE_VCACHE = cache;
}

void e3dBeginIndexed (e3dVertexCache* vertex, e3dIndexCache* index)
{
  E3D_IMMEDIATE_VCACHE = vertex;
  E3D_IMMEDIATE_ICACHE = index;
}

void e3dColor3f (float r, float g, float b)
{
  E3D_IMMEDIATE_VTX.color [0] = (char)(255.0f * r);
  E3D_IMMEDIATE_VTX.color [1] = (char)(255.0f * g);
  E3D_IMMEDIATE_VTX.color [2] = (char)(255.0f * b);
  E3D_IMMEDIATE_VTX.color [3] = 255; // Assume opaque
}

void AddVertex (e3dVertexCache* vcache, e3dIndexCache* icache, const e3dVertex vtx)
{
  if (vcache) {
    size_t       size = vcache->GetSize () + 1;
    unsigned int idx  = (unsigned int)(size - 1);

    vcache->Resize    (size);
    vcache->SetVertex (idx, vtx);

    if (icache) {
      size_t       i_size = icache->GetSize () + 1;
      unsigned int i_idx  = (unsigned int)(i_size - 1);

      icache->Resize   (i_size);
      icache->SetIndex (i_idx, (e3dIndex)(size - 1));
    }
  }
}

void e3dVertex3f (float x, float y, float z)
{
  E3D_IMMEDIATE_VTX.pos [0] = x;
  E3D_IMMEDIATE_VTX.pos [1] = y;
  E3D_IMMEDIATE_VTX.pos [2] = z;

  AddVertex (E3D_IMMEDIATE_VCACHE, E3D_IMMEDIATE_ICACHE, E3D_IMMEDIATE_VTX);
}

void e3dNormal3f (float x, float y, float z)
{
  E3D_IMMEDIATE_VTX.normal [0] = x;
  E3D_IMMEDIATE_VTX.normal [1] = y;
  E3D_IMMEDIATE_VTX.normal [2] = z;
}

void e3dTangent3f (float x, float y, float z)
{
  E3D_IMMEDIATE_VTX.tangent [0] = x;
  E3D_IMMEDIATE_VTX.tangent [1] = y;
  E3D_IMMEDIATE_VTX.tangent [2] = z;
}

void e3dTexCoord2f (float u, float v)
{
  E3D_IMMEDIATE_VTX.st [0] = u;
  E3D_IMMEDIATE_VTX.st [1] = v;
}

void e3dEnd (void)
{
  //
  // THIS CODE IS WAY TOO SLOW, DON'T BOTHER...
  //
  /*
  // Combine duplicate vertices if we're using an index cache...
  if (E3D_IMMEDIATE_ICACHE != NULL && E3D_IMMEDIATE_VCACHE->GetSize () == 6) {
    for (int i = 0; i < E3D_IMMEDIATE_VCACHE->GetSize (); i++) {
      e3dVertex test_vtx = E3D_IMMEDIATE_VCACHE->GetVertex (i);

      for (int j = 0; j < E3D_IMMEDIATE_VCACHE->GetSize (); j++) {
        e3dVertex vtx = E3D_IMMEDIATE_VCACHE->GetVertex (j);

        if (j == i)
          continue;

        if ((vtx.color [0] == test_vtx.color [0] &&
             vtx.color [1] == test_vtx.color [1] &&
             vtx.color [2] == test_vtx.color [2] &&
             vtx.color [3] == test_vtx.color [3])   &&
            (vtx.pos [0] == test_vtx.pos [0] &&
             vtx.pos [1] == test_vtx.pos [1] &&
             vtx.pos [2] == test_vtx.pos [2])   &&
            (vtx.st [0] == test_vtx.st [0] &&
             vtx.st [1] == test_vtx.st [1])) {
          printf ("Vertex: %d is a duplicate of %d\n", j, i);
        }
      }
    }
  }
  */

  E3D_IMMEDIATE_VCACHE  = NULL;
  E3D_IMMEDIATE_ICACHE  = NULL;

  E3D_IMMEDIATE_VTX.color [0] = (char)255;
  E3D_IMMEDIATE_VTX.color [1] = (char)255;
  E3D_IMMEDIATE_VTX.color [2] = (char)255;
  
  // If we were using VBOs, this tells it to upload the
  // new vertex data to the GPU.
  ///E3D_IMMEDIATE_VCACHE->Commit ();
}
